﻿#include "GraphVTKObjectModel.h"
#include "GraphDataVTKPartSetManager.h"
#include "RadiossVTKGraphActor.h"
#include "GraphVTKObjectHighlighting.h"

#include "FITK_Kernel/FITKAppFramework/FITKAppFramework.h"
#include "FITK_Kernel/FITKAppFramework/FITKGlobalData.h"
#include "FITK_Kernel/FITKAppFramework/FITKRunTimeSetting.h"

#include "FITK_Interface/FITKVTKAlgorithm/FITKGraphActor.h"
#include "FITK_Interface/FITKInterfaceGeometry/FITKAbsGeoCommand.h"
#include "FITK_Interface/FITKInterfaceGeometry/FITKAbsGeoShapeAgent.h"
#include "FITK_Interface/FITKInterfaceGeometry/FITKVirtualTopoManager.h"
#include "FITK_Interface/FITKInterfaceGeometry/FITKGeometryMeshVS.h"
#include "FITK_Interface/FITKInterfaceGeometry/FITKGeometryMeshEntity.h"
#include "FITK_Interface/FITKInterfaceGeometry/FITKGeoCommandProp.h"

#include <vtkObject.h>
#include <vtkProperty.h>
#include <vtkUnstructuredGrid.h>
#include <vtkUnsignedCharArray.h>
#include <vtkPolyData.h>
#include <vtkPoints.h>
#include <vtkIdList.h>
#include <vtkCellType.h>
#include <vtkCellArray.h>
#include <vtkCellData.h>
#include <vtkDoubleArray.h>
#include <vtkPointData.h>
#include <vtkPolygon.h>

namespace Exchange
{
    GraphVTKObjectModel::GraphVTKObjectModel(Interface::FITKAbsGeoCommand* geoCommand)
        : GraphVTKObjectModelBase(geoCommand)
    {
        if (!geoCommand) {
            return;
        }

        // 生成可视化数据
        if (!generateDataSet()) {
            return;
        }

        // 生成可视化对象
        generateGraph();
    }

    GraphVTKObjectModel::~GraphVTKObjectModel()
    {

    }

    void GraphVTKObjectModel::setPickMode(GraphVTKCommons::ShapePickMode mode)
    {
        // Lambda for set actor pickable.
        auto setActorPickable = [=](RadiossVTKGraphActor* fActor, bool isOn) {
            if (fActor) {
                fActor->SetPickable(isOn);
            }
            };

        switch (mode) {
        case GraphVTKCommons::PickNone:
            setActorPickable(_pointActor, false);
            setActorPickable(_lineActor, false);
            setActorPickable(_faceActor, false);
            setActorPickable(_solidActor, false);
            break;
        case GraphVTKCommons::PickGeoVertex:
            setActorPickable(_pointActor, true);
            setActorPickable(_lineActor, false);
            setActorPickable(_faceActor, false);
            setActorPickable(_solidActor, false);
            break;
        case GraphVTKCommons::PickGeoEdge:
            setActorPickable(_pointActor, false);
            setActorPickable(_lineActor, true);
            setActorPickable(_faceActor, false);
            setActorPickable(_solidActor, false);
            break;
        case GraphVTKCommons::PickGeoFace:
            setActorPickable(_pointActor, false);
            setActorPickable(_lineActor, false);
            setActorPickable(_faceActor, true);
            setActorPickable(_solidActor, false);
            break;
        case GraphVTKCommons::PickGeoSolid:
            setActorPickable(_pointActor, false);
            setActorPickable(_lineActor, false);
            setActorPickable(_faceActor, false);
            setActorPickable(_solidActor, true);
            break;
        default:
            return;
        }

        //记录拾取类型
        GraphVTKObject3D::setPickMode(mode);
    }

    int GraphVTKObjectModel::getShapeIdByVTKCellId(int vtkCellId, GraphVTKCommons::ShapePickMode pickType, QVariant otherInfo)
    {
        int id = -1;
        if (vtkCellId < 0) {
            return id;
        }

        // 从管理器中获取当前数据对象的信息
        GraphDataVTKPartSetManager* partSetManager = GraphDataVTKPartSetManager::getInstance();
        Interface::FITKAbsGeoCommand* geoCommand = dynamic_cast<Interface::FITKAbsGeoCommand*>(_dataObj);
        if (geoCommand == nullptr) return id;

        GraphDataVTKPartSetInfo* geoInfo = partSetManager->getGeoCommandInfo(geoCommand->getDataObjectID());
        if (geoInfo == nullptr) return id;

        switch (pickType) {
        case GraphVTKCommons::ShapePickMode::PickGeoSolid: id = geoInfo->_solid_VTKId_CellID.value(vtkCellId); break;
        case GraphVTKCommons::ShapePickMode::PickGeoFace: id = geoInfo->_face_VTKId_CellID.value(vtkCellId); break;
        case GraphVTKCommons::ShapePickMode::PickGeoEdge: id = geoInfo->_line_VTKId_CellID.value(vtkCellId); break;
        case GraphVTKCommons::ShapePickMode::PickGeoVertex: id = geoInfo->_point_VTKId_CellID.value(vtkCellId); break;
        }
        return id;
    }

    const QVector<int> GraphVTKObjectModel::getVTKCellIdsByShapeId(int shapeId, GraphVTKCommons::ShapePickMode pickType, QVariant otherInfo)
    {
        QVector<int> cellIds;

        // 从管理器中获取当前数据对象的信息
        GraphDataVTKPartSetManager* partSetManager = GraphDataVTKPartSetManager::getInstance();
        Interface::FITKAbsGeoCommand* geoCommand = dynamic_cast<Interface::FITKAbsGeoCommand*>(_dataObj);
        if (geoCommand == nullptr) return cellIds;

        GraphDataVTKPartSetInfo* geoInfo = partSetManager->getGeoCommandInfo(geoCommand->getDataObjectID());
        if (geoInfo == nullptr) return cellIds;

        switch (pickType) {
        case GraphVTKCommons::ShapePickMode::PickGeoSolid: {
            QList<int> vtkIDs = geoInfo->_solid_VTKId_CellID.keys(shapeId);
            for (int vtkID : vtkIDs) {
                cellIds.append(vtkID);
            }
            break;
        }
        case GraphVTKCommons::ShapePickMode::PickGeoFace: {
            QList<int> vtkIDs = geoInfo->_face_VTKId_CellID.keys(shapeId);
            for (int vtkID : vtkIDs) {
                cellIds.append(vtkID);
            }
            break;
        }
        case GraphVTKCommons::ShapePickMode::PickGeoEdge: {
            cellIds.append(geoInfo->_line_VTKId_CellID.key(shapeId));
            break;
        }
        case GraphVTKCommons::ShapePickMode::PickGeoVertex: {
            cellIds.append(geoInfo->_point_VTKId_CellID.key(shapeId));
            break;
        }
        }

        return cellIds;
    }

    int GraphVTKObjectModel::getVirTopoIndexByShapeId(int shapeId, GraphVTKCommons::ShapePickMode pickType)
    {
        // 获取当前数据对象的信息
        GraphDataVTKPartSetManager* partSetManager = GraphDataVTKPartSetManager::getInstance();
        Interface::FITKAbsGeoCommand* geoCommand = dynamic_cast<Interface::FITKAbsGeoCommand*>(_dataObj);
        if (geoCommand == nullptr) return -1;
        GraphDataVTKPartSetInfo* geoInfo = partSetManager->getGeoCommandInfo(geoCommand->getDataObjectID());
        if (geoInfo == nullptr) return -1;

        switch (pickType) {
        case GraphVTKCommons::PickGeoVertex:
            return geoInfo->_pointVirTopoIdToIndex.value(shapeId, -1);
        case GraphVTKCommons::PickGeoEdge:
            return geoInfo->_lineVirTopoIdToIndex.value(shapeId, -1);
        case GraphVTKCommons::PickGeoFace:
            return geoInfo->_faceVirTopoIdToIndex.value(shapeId, -1);
        case GraphVTKCommons::PickGeoSolid:
            return geoInfo->_solidVirTopoIdToIndex.value(shapeId, -1);
        default:
            return -1;
        }
    }

    vtkDataSet* GraphVTKObjectModel::getMesh(GraphVTKCommons::ShapePickMode pickType)
    {
        // 从管理器中获取当前数据对象的信息
        GraphDataVTKPartSetManager* partSetManager = GraphDataVTKPartSetManager::getInstance();
        Interface::FITKAbsGeoCommand* geoCommand = dynamic_cast<Interface::FITKAbsGeoCommand*>(_dataObj);
        if (geoCommand == nullptr) return nullptr;

        GraphDataVTKPartSetInfo* geoInfo = partSetManager->getGeoCommandInfo(geoCommand->getDataObjectID());
        if (geoInfo == nullptr) return nullptr;

        switch (pickType) {
        case GraphVTKCommons::ShapePickMode::PickGeoVertex:
            return geoInfo->_pointGrid;
        case GraphVTKCommons::ShapePickMode::PickGeoEdge:
            return geoInfo->_lineGrid;
        case GraphVTKCommons::ShapePickMode::PickGeoFace:
            return geoInfo->_faceGrid;
        case GraphVTKCommons::ShapePickMode::PickGeoSolid:
            return geoInfo->_solidGrid;
        }
        return nullptr;
    }

    void GraphVTKObjectModel::update(bool forceUpdate)
    {
        updateVisibility();
        if (forceUpdate == true) {
            generateDataSet();
        }
    }

    void GraphVTKObjectModel::setVisible(bool visibility)
    {
        if (_pointActor == nullptr || _lineActor == nullptr || _faceActor == nullptr || _solidActor == nullptr)return;
        _pointActor->SetVisibility(visibility);
        _lineActor->SetVisibility(visibility);
        _faceActor->SetVisibility(visibility);
        _solidActor->SetVisibility(visibility);
        _isVisible = visibility;
    }

    void GraphVTKObjectModel::setCellVisible(bool visibility)
    {
        _faceActor->SetVisibility(visibility);
        _solidActor->SetVisibility(visibility);
    }

    void GraphVTKObjectModel::setPointVisibility(bool visibility)
    {
        _pointActor->SetVisibility(visibility);
    }

    void GraphVTKObjectModel::setLineVisibility(bool visibility)
    {
        _lineActor->SetVisibility(visibility);
    }

    bool GraphVTKObjectModel::getVisibility()
    {
       //获取数据可见性
        bool isEnable = this->Superclass::getVisibility();
        //判断引用关系可见性
        bool beReferenced = false;
        Interface::FITKAbsGeoCommand* cmd = dynamic_cast<Interface::FITKAbsGeoCommand*>(_dataObj);
        if (cmd == nullptr) return false;
        //是否开启引用计数状态
        beReferenced = cmd->getEnableReferenceList();
        //判断是否是被删除获取被编辑状态
        beReferenced &= cmd->getCommandStatus() != Interface::FITKGeoEnum::FITKGeoStatus::FGSDeleted &&
            cmd->getCommandStatus() != Interface::FITKGeoEnum::FITKGeoStatus::FGSModified;
        //获取当前命令是被引用数量
        beReferenced &= (cmd->getReferencedCmdCount() == 0);
        return beReferenced &= isEnable;
    }

    void GraphVTKObjectModel::updateVisibility()
    {
        bool isVisibility = getVisibility();
        AppFrame::FITKRunTimeSetting* runSetting = FITKAPP->getGlobalData()->getRunTimeSetting();
        //获取点显示状态
        bool visible = true;
        visible = runSetting->getValue("GeoPoint").toBool();
        _pointActor->SetVisibility(isVisibility && visible);
        //获取线显示状态
        visible = runSetting->getValue("GeoLine").toBool();
        _lineActor->SetVisibility(isVisibility && visible);
        //获取几何显示状态
        visible = runSetting->getValue("Geo").toBool();
        _faceActor->SetVisibility(isVisibility && visible);
        _solidActor->SetVisibility(isVisibility && visible);
    }

    void Exchange::GraphVTKObjectModel::updateModelColor(QColor color)
    {
        if (_faceActor)
        _faceActor->GetProperty()->SetColor(color.redF(), color.greenF(), color.blueF());
        if (_solidActor)
        _solidActor->GetProperty()->SetColor(color.redF(), color.greenF(), color.blueF());
    }
    bool GraphVTKObjectModel::generateDataSet()
    {
        Interface::FITKAbsGeoCommand* geoCommand = dynamic_cast<Interface::FITKAbsGeoCommand*>(_dataObj);
        GraphDataVTKPartSetManager* partSetManager = GraphDataVTKPartSetManager::getInstance();
        if (geoCommand == nullptr || partSetManager == nullptr) return false;

        int geoCommandId = geoCommand->getDataObjectID();
        partSetManager->updateGeoCommand(geoCommandId);
        return true;
    }

    void GraphVTKObjectModel::generateGraph()
    {
        Interface::FITKAbsGeoCommand* geoCommand = dynamic_cast<Interface::FITKAbsGeoCommand*>(_dataObj);
        GraphDataVTKPartSetManager* partSetManager = GraphDataVTKPartSetManager::getInstance();
        if (geoCommand == nullptr || partSetManager == nullptr) return;
        Interface::FITKGeoCommandProp* porp = geoCommand->getCommandProp();
        if (porp == nullptr) return;
        QColor color = porp->getColor();
        int geoCommandId = geoCommand->getDataObjectID();
        GraphDataVTKPartSetInfo* geoInfo = partSetManager->getGeoCommandInfo(geoCommandId);
        if (geoInfo == nullptr) return;
        this->setRenderLayer(0);

        //获取运行时设置
        AppFrame::FITKRunTimeSetting* runSetting = FITKAPP->getGlobalData()->getRunTimeSetting();
        //获取点显示状态
        bool visible = true;
        visible = runSetting->getValue("GeoPoint").toBool();

        // 创建点演员
        _pointActor = RadiossVTKGraphActor::New();
        // 演员中存储渲染对象
        _pointActor->setGraphObject(this);
        _pointActor->setActorType(ActorType::VertexActor);
        _pointActor->SetPickable(false);
        _pointActor->SetVisibility(visible);
        _pointActor->GetProperty()->SetPointSize(5);
        _pointActor->GetProperty()->SetOpacity(1);
        QColor pointColor = GraphVTKCommons::_geoVertexColor;
        _pointActor->GetProperty()->SetColor(pointColor.redF(), pointColor.greenF(), pointColor.blueF());
        _pointActor->setInputDataObject(geoInfo->_pointGrid);
        // 设置偏移参数
        _pointActor->setRelativeCoincidentTopologyPolygonOffsetParameters(GraphVTKCommons::_geoGraphOffset,2);
        addActor(_pointActor);

        //获取线显示状态
        visible = runSetting->getValue("GeoLine").toBool();
        // 创建线演员
        _lineActor = RadiossVTKGraphActor::New();
        // 演员中存储渲染对象
        _lineActor->setGraphObject(this);
        _lineActor->setActorType(ActorType::EdgeActor);
        _lineActor->SetPickable(false);
        _lineActor->SetVisibility(visible);
        _lineActor->GetProperty()->SetLineWidth(2);
        //QColor lineColor = GraphVTKCommons::_geoEdgeColor;
        _lineActor->GetProperty()->SetColor(0,0,0);
        _lineActor->setInputDataObject(geoInfo->_lineGrid);
        // 设置偏移参数
        _lineActor->setRelativeCoincidentTopologyPolygonOffsetParameters(GraphVTKCommons::_geoGraphOffset,2);
        addActor(_lineActor);

        //获取几何显示状态
        visible = runSetting->getValue("Geo").toBool();
        // 创建面演员
        _faceActor = RadiossVTKGraphActor::New();
        // 演员中存储渲染对象
        _faceActor->setGraphObject(this);
        _faceActor->setActorType(ActorType::SurfaceActor);
        _faceActor->SetPickable(false);
        _faceActor->SetVisibility(visible);
        _faceActor->GetProperty()->SetRepresentation(2);
        _faceActor->GetProperty()->SetEdgeVisibility(false);
        _faceActor->GetProperty()->SetColor(color.redF(), color.greenF(), color.blueF());
        _faceActor->setInputDataObject(geoInfo->_faceGrid);
        // 设置偏移参数
        _faceActor->setRelativeCoincidentTopologyPolygonOffsetParameters(GraphVTKCommons::_geoGraphOffset,2);
        addActor(_faceActor);

        // 创建体演员
        _solidActor = RadiossVTKGraphActor::New();
        // 演员中存储渲染对象
        _solidActor->setGraphObject(this);
        _solidActor->setActorType(ActorType::SolidActor);
        _solidActor->SetPickable(false);
        _solidActor->SetVisibility(visible);
        _solidActor->GetProperty()->SetRepresentation(2);
        _solidActor->GetProperty()->SetEdgeVisibility(false);
        _solidActor->GetProperty()->SetColor(color.redF(), color.greenF(), color.blueF());
        _solidActor->setInputDataObject(geoInfo->_solidGrid);
        //设置偏移参数
        _solidActor->setRelativeCoincidentTopologyPolygonOffsetParameters(GraphVTKCommons::_geoGraphOffset,2);
        addActor(_solidActor);

        m_graphObjHighlight->setModelInputDataObject(geoInfo->_lineGrid);
        m_graphObjHighlight->setActorType(2); //边界高亮
    }
}   // namespace Exchange
